/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2003-2010 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_DesFire_EV1.c
  -----------------

  This is the reference applications that validates the whole SpringProx API
  for NXP DESFire EV1 cards.
  
  JDA 01/13/2010 : initial release

*/
#include "products/springprox/springprox.h"
#include "cardware/desfire/sprox_desfire.h"

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef __linux__
#include <sys/time.h>
#endif

void DesFire_xDES_Recv(BYTE * data, WORD blocks, const BYTE * key);

//#define LOOP_TEST

#ifdef WIN32
#ifdef LOOP_TEST
#define CHECK_RC() { if (rc!=0) { Beep(880,1000); printf("\nline %d, mode %d - failed (%d) %s\n", __LINE__-1, level, rc, SPROX_Desfire_GetErrorMessage(rc)); err_count++; goto tag_halt; } printf("."); fflush(NULL); }
#else
#define CHECK_RC() { if (rc!=0) { printf("\nline %d, mode %d - failed (%d) %s\n", __LINE__-1, level, rc, SPROX_Desfire_GetErrorMessage(rc)); goto tag_halt; } printf("."); fflush(NULL); }
#endif
#endif

#ifdef __linux__
#define CHECK_RC() { if (rc!=0) { printf("\nline %d, mode %d - failed (%d) %s\n", __LINE__-1, level, rc, SPROX_Desfire_GetErrorMessage(rc)); goto tag_halt; } printf("."); fflush(NULL); }
#endif

#ifdef LOOP_TEST
WORD loop_count = 0;
WORD err_count = 0;
#endif

#define LEVEL_LEGACY          0x01
#define LEVEL_3DES3K          0x02
#define LEVEL_LEGACY_3DES3K   0x03
#define LEVEL_AES             0x04


const BYTE abNullKey[24]      = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

const BYTE abRootKey1[24]     = { "ABCDEFGHABCDEFGHABCDEFGH" };
const BYTE abRootKey2[24]     = { "Card Master Key!Card Mas" };

const BYTE abSingleDesKey[24] = { "SglDES_1SglDES_1SglDES_1" };

const BYTE abTestKeyDes[24]   = { "ABCDEFGHABCDEFGHABCDEFGH" };
const BYTE abTestKey3Des2[24] = { "ABCDEFGHIJKLMNOPABCDEFGH" };
const BYTE abTestKey3Des3[24] = { "ABCDEFGHIJKLMNOPQRSTUVWX" };


const BYTE appBMasterKey0[24] = { "App.B Master KeyApp.B Ma" };
const BYTE appBMasterKey1[24] = { "@qq/C!L`ruds!Kdx@qq/C!L`" };
const BYTE appBChangeKey[24]  = { "B's Chg Keys KeyB's Chg " };

const BYTE appBKey1[24]       = { "App.B Key #1.   App.B Ke" };
const BYTE appBKey2[24]       = { "App.B Key #2..  App.B Ke" };
const BYTE appBKey3[24]       = { "App.B Key #3... App.B Ke" };
const BYTE appBKey4[24]       = { "App.B Key #4....App.B Ke" };

const BYTE appCKey1[24]       = { "App.C Key #1.   App.C Ke" };
const BYTE appCKey2[24]       = { "App.C Key #2..  App.C Ke" };
const BYTE appCKey3[24]       = { "App.C Key #3... App.C Ke" };
const BYTE appCKey4[24]       = { "App.C Key #4....App.C Ke" };


/* Budrate in each direction */
BYTE want_dsi_dri = 0;

int main(int argc, char **argv)
{
  SWORD rc;
  int i;
  char s_buffer[64];
  BYTE cid = 0xFF;
  BYTE atq[2];
  BYTE sak[1];
  BYTE snr[12];
  BYTE snrlen = 12;
  BYTE ats[32];
  BYTE atslen = 32;
  BYTE level;
  BOOL is_legacy_card = FALSE;

  char *device = NULL;

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("NXP DESFIRE EV1 reference demo (DES/3DES2K/3DES3K/AES)\n");
  printf("------------------------------------------------------\n");
  printf("www.springcard.com\n\n");

  for (i=1; i<argc; i++)
  {
    if (!strcmp(argv[i], "-b0")) want_dsi_dri = 0; else
    if (!strcmp(argv[i], "-b1")) want_dsi_dri = 1; else
    if (!strcmp(argv[i], "-b2")) want_dsi_dri = 2; else
    if (!strcmp(argv[i], "-b3")) want_dsi_dri = 3; else
    if (i == argc-1)
    {
      device = argv[i];
      printf("Device : '%s'\n", device);
    } else
    {
      printf("usage: ref_desfire [-b0|-b1|-b2|-b3] [device]\n");
      printf("       -b0 : set baudrate to 106kbit/s\n");
      printf("       -b1 : set baudrate to 212kbit/s\n");
      printf("       -b2 : set baudrate to 424kbit/s\n");
      printf("       -b3 : set baudrate to 848kbit/s\n");
      printf("\n");
      return 0;
    }
  }

  rc = SPROX_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");


  SPROX_Desfire_SelectCid(cid);


#ifdef LOOP_TEST
  for (;;)
  {
#endif

    /* Open reader */
    /* ----------- */
  
    rc = SPROX_ReaderOpen(device);
    if (rc != MI_OK)
    {
      printf("Reader not found\n");
      goto done;
    }
  
    rc = SPROX_ReaderGetDevice(s_buffer, sizeof(s_buffer));
    if (rc == MI_OK)
      printf("Reader found on %s\n", s_buffer);
  
    rc = SPROX_ReaderGetFirmware(s_buffer, sizeof(s_buffer));
    if (rc == MI_OK)
      printf("Reader firwmare is %s\n", s_buffer);

    /* Configure reader in ISO 14443-A mode */
    /* ------------------------------------ */
    rc = SPROX_SetConfig(CFG_MODE_ISO_14443_A);
    if (rc != MI_OK)
    {
      printf("Failed to configure the reader\n");
      goto close;
    }

    /* RF field ON */
    SPROX_ControlRF(TRUE);

    /* Select any tag in the ISO 14443-A RF field */
    /* ------------------------------------------ */
  next_tag:

    printf("Waiting for a tag...\n");

    rc = SPROX_TclA_ActivateIdle(atq, snr, &snrlen, sak);
    if (rc == MI_CARD_NOT_TCL)
    {
      /* On a bien trouve un badge, mais il s'arrete au type 3 */
      printf("The selected tag is not ISO 14443-4 (T=CL)\n");
      goto tag_halt;
    }
    if (rc == MI_NOTAGERR)
    {
      /* Pas de badge dans le champ */
      printf("No available tag in RF field\n");
      goto close;
    }
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to select tag\n");
      goto close;
    }

    printf("T=CL tag found, SNR=");
    for (i = 0; i < snrlen; i++)
      printf("%02X", snr[i]);
    printf(" ATQ=%02X%02X SAK=%02X\n", atq[1], atq[0], sak[0]);

    /* Is the tag a DESFire ? */
    /* ---------------------- */
    if ( (atq[1] != 0x03) || ( (atq[0] != 0x44) && (atq[0] != 0x04) ))
    {
      printf("This is not a DESFire tag\n");
      goto tag_halt;
    }

    /* Open a T=CL session on the tag */
    /* ------------------------------ */
    rc = SPROX_TclA_GetAts(cid, ats, &atslen);
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to activate the tag (%d)\n", rc);
      goto tag_halt;
    }

    printf("T=CL tag activated, ATS=");
    for (i = 0; i < atslen; i++)
      printf("%02X", ats[i]);
    printf(" (TA1=%02X TA2=%02X TA3=%02X)\n", ats[2], ats[3], ats[4]);

    /* PPS is not really interesting since we stay at 106kbps */
    rc = SPROX_TclA_Pps(cid, want_dsi_dri, want_dsi_dri);
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to negociate PPS (DSI=DRI=%d)\n", want_dsi_dri);
      goto tag_stop;
    }
    printf("PPS OK, DSI=DRI=%d\n", want_dsi_dri);

    /* Check DESFire library functions */
    /* ------------------------------- */

    for (level = 1; level <= 4; level++)
    {

		  SWORD rc;
		  LONG lAmount;
		  BYTE bCommMode, bKeyVersion;
		  DWORD eNRecordsRead, eOffset, dwFreeBytes = 4096;
		  BYTE abCardMasterKey[24];
		  BYTE bStdDataFileID, bFileType, bNFilesFound, bNApplicationsFound;
		  BYTE bTemp;
		  DWORD dwNbBytesRead;
		  DWORD adwApplications[32];
		  BYTE abDataBuffer[8192];
		  WORD wDesFireSoftwareVersion, wAccessRights;
		  BOOL trace = FALSE;
		  BOOL beep  = TRUE;
		  int i, iTransaction, iFileIndex;
		
		  DF_VERSION_INFO stVersionInfo;
		  DF_ADDITIONAL_FILE_SETTINGS unFileSettings;

      switch (level)
      {
        case LEVEL_LEGACY        : printf("Desfire EV0 compatibility test (DES/3DES2K)\n");
                                   break;

        case LEVEL_3DES3K        : if (is_legacy_card) continue;
                                   printf("Desfire EV1, ISO mode with 3DES3K\n");
                                   break;
        case LEVEL_LEGACY_3DES3K : if (is_legacy_card) continue;
                                   printf("Desfire EV1, legacy mode with 3DES3K\n");
                                   break;
        case LEVEL_AES           : if (is_legacy_card) continue;
                                   printf("Desfire EV1, ISO mode with AES\n");
                                   break;
      }
		
		next_run:
		
		  //  After activating a DesFire card the currently selected 'application' is the card
		  //  level (AID = 0). Therefore the next command is redundant.
		  //  We use the command to check that the card is responding correctly.
		  rc = SPROX_Desfire_SelectApplication(0);
		  CHECK_RC();
			
		  //  Get the card's version information.
		  rc = SPROX_Desfire_GetVersion(&stVersionInfo);
		  CHECK_RC();
		  wDesFireSoftwareVersion =
		    (unsigned int) ((unsigned int) stVersionInfo.
		                    bSwMajorVersion << 8 | stVersionInfo.bSwMinorVersion);
		
      if (wDesFireSoftwareVersion < 0x0100)
      {
        if (!is_legacy_card)
          printf("\nThis is a Desfire EV0 - ref_desfire would run better with this card !\n");
        is_legacy_card = TRUE;
      }

      if (!is_legacy_card)
      {
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  Which Card Master Key is currently in use ?
		  //  Beginning with DesFire version 0.1 the GetKeyVersion command can help determining
		  //  which key is currently effective.
		  rc = SPROX_Desfire_GetKeyVersion(0, &bKeyVersion);
		  CHECK_RC();
		
		  //  Authenticate with the key which corresponds to the retieved key version.
		  if (bKeyVersion == 0)
		  {
		    rc = SPROX_Desfire_Authenticate(0, abNullKey);
		  } else
		  if (bKeyVersion == 0xAA)
		  {
		    rc = SPROX_Desfire_Authenticate(0, abRootKey1);
		  } else
		  if (bKeyVersion == 0xC7)
		  {
		    rc = SPROX_Desfire_Authenticate(0, abRootKey2);
		  } else
		  {
		    //  Who knows the key ?
		    printf("Sorry, the master key is unknown (version = %02X)\n",
		           bKeyVersion);
		    return FALSE;
		  }
		  CHECK_RC();
		
		  if (bKeyVersion != 0x00)
		  {
		    printf("Current master key version is %02X\n", bKeyVersion);
		    rc = SPROX_Desfire_GetKeySettings(&abDataBuffer[0], &abDataBuffer[1]);
		    CHECK_RC();
		
		    printf("Root application key settings are %02X %02X\n",
		           abDataBuffer[0], abDataBuffer[1]);
		
		    //  Try to allow to change the key
		    rc = SPROX_Desfire_ChangeKeySettings(0xF);
		    CHECK_RC();
		
		    //  Back to blank key
		    rc = SPROX_Desfire_ChangeKey(0, abNullKey, NULL);
		    CHECK_RC();
		
		    //  Authenticate again
		    rc = SPROX_Desfire_Authenticate(0, abNullKey);
		    CHECK_RC();
		
		    //  Startup with a blank card !!!
		    printf("Formatting the tag\n");
		    rc = SPROX_Desfire_FormatPICC();
		    CHECK_RC();
		
		    goto next_run;
		  }
		
      if (!is_legacy_card)
      {
		    // Get the UID of the card
		    rc = SPROX_Desfire_GetCardUID(abDataBuffer);
		    CHECK_RC();
      }
      		
		  //  Change the Card master key to a SingleDES key.
		  memcpy(abCardMasterKey, abRootKey1, 24);
		  rc = SPROX_Desfire_ChangeKey(0, abCardMasterKey, NULL);
		  CHECK_RC();
		  rc = SPROX_Desfire_GetKeyVersion(0, &bKeyVersion);
		  CHECK_RC();
		
		
		  //  Use a TripleDES key as the Application Master Key.
		  if ((level & LEVEL_3DES3K) || (level & LEVEL_AES))
		  {
		    rc = SPROX_Desfire_Authenticate24(0, abCardMasterKey);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		    CHECK_RC();
		  }
		
		/*
		  // Reconfigure the card
		  {
		    BYTE b = 0x02;
		    //BYTE ats[] = { 0x06, 0x75, 0x77, 0x81, 0x02, 0xFF };
		    //rc = SPROX_Desfire_SetConfiguration(0x02, ats, sizeof(ats));
		    rc = SPROX_Desfire_SetConfiguration(0x00, &b, 1);
		    CHECK_RC();
		  }
		*/
		
		  //  Change the Card master key to a TripleDES key.
		  memcpy(abCardMasterKey, abRootKey2, 24);
		
		  if ((level & LEVEL_3DES3K) || (level & LEVEL_AES))
		  {
		    rc = SPROX_Desfire_ChangeKey24(0, abCardMasterKey, NULL); // JDA
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_ChangeKey(0, abCardMasterKey, NULL);
		    CHECK_RC();
		  }

      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }

		  rc = SPROX_Desfire_GetKeyVersion(0, &bKeyVersion);
		  CHECK_RC();
		  rc = SPROX_Desfire_GetKeyVersion(0, &bKeyVersion);
		  CHECK_RC();
		
		  if ((level & LEVEL_3DES3K) || (level & LEVEL_AES))
		  {
		    rc = SPROX_Desfire_Authenticate24(0, abCardMasterKey);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		    CHECK_RC();
		  }
		
		  rc = SPROX_Desfire_GetKeySettings(&abDataBuffer[0], &abDataBuffer[1]);
		  CHECK_RC();

      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  At this point we would like to begin with a blank card.
		  rc = SPROX_Desfire_FormatPICC();
		  CHECK_RC();
		
      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  Create three applications:
		
		  //  Application A is the most open one.
		  //  It has no keys and its key settings are least restrictive.
		  //  Note: since there are no keys, the Change Keys key settting must be assigned
		  //        the value 0xE or 0xF.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xAAAAAA, 0xFF, DF_APPLSETTING2_AES | 0);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xAAAAAA, 0xFF, DF_APPLSETTING2_3DES3K | 0);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_CreateApplication(0xAAAAAA, 0xFF, 0);
		    CHECK_RC();
		  }
		
		  //  Application B's key settings can be changed at a later time.
		  //  It has six keys.
		  //  Authentication with a given key allows also to change that key.
		  //  (the Change Keys key settting is 0xE)
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xBBBBBB, 0xEF, DF_APPLSETTING2_AES | 6);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xBBBBBB, 0xEF, DF_APPLSETTING2_3DES3K | 6);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_CreateApplication(0xBBBBBB, 0xEF, 6);
		    CHECK_RC();
		  }
		
		  //  Application C keeps everything private.
		  //  Even getting its file directory is not publicly allowed.
		  //  The application has the maximum of 14 keys.
		  //  We make key #0xC the Change Keys key.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, DF_APPLSETTING2_AES | 14);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, DF_APPLSETTING2_3DES3K | 14);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, 14);
		    CHECK_RC();
		  }
		
		  //  Verify that the applications have been created.
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		
		  // New applications for ISO testing 
      if (!is_legacy_card)
      {
		    rc = SPROX_Desfire_CreateIsoApplication(0xFF0001, 0xFF, 0, 0x2000, "1TIC.ICA", 8);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateIsoApplication(0xFF0002, 0xFF, 0, 0x3000, "2MPP.EPP", 8);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateIsoApplication(0xFF0003, 0xFF, 0, 0x4000, "3JDA.JDA", 8);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateIsoApplication(0xFF3F00, 0xFF, 0, 0x3F00, "AAAABBBBCCCCDDDD", 16);
		    CHECK_RC();
      }
		
		  // More applications
		  if (dwFreeBytes > 4096)
		  {
		    rc = SPROX_Desfire_CreateApplication(0xFFFF00, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF01, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF02, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF03, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF04, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF05, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF06, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF07, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF08, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0A, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0B, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0C, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0D, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0E, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF0F, 0xFF, 0);
		    CHECK_RC();
		
		    rc = SPROX_Desfire_CreateApplication(0xFFFF10, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF20, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF30, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF40, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF50, 0xFF, 0);
		    CHECK_RC();
		    rc = SPROX_Desfire_CreateApplication(0xFFFF60, 0xFF, 0);
		    CHECK_RC();
		  }
		
		  //  Verify that the applications have been created.
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		
		  // Cleanup authentication state
		  rc = SPROX_Desfire_SelectApplication(0);
		  CHECK_RC();
		  
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		
		
		  bStdDataFileID = 15;
		
		  //  Create the files in application A:
		  //  Since the application does not have any keys associated with it, the file access rights
		  //  settings 0xE (public access granted) and 0xF (access denied) are the only permissable
		  //  ones.
		  rc = SPROX_Desfire_SelectApplication(0xAAAAAA);
		  CHECK_RC();
		
		  //  Create a the Standard Data file.
		  rc = SPROX_Desfire_CreateStdDataFile(bStdDataFileID, 0, 0xEEEE, 640);
		  CHECK_RC();
		
		  //  Create a 64 byte Backup file.
		  rc = SPROX_Desfire_CreateBackupDataFile(5, 0, 0xEEEE, 64);
		  CHECK_RC();
		
		  //  Create a Value file allowing values from 0 to 1000.
		  //  The initial value is 0.
		  //  The Limited Credit feature is disabled.
		  rc = SPROX_Desfire_CreateValueFile(4, 0, 0xEEEE, 0, 1000, 0, 0);
		  CHECK_RC();
		
		  //  And finally create a Cyclic Record file capable of holding 10 records of 4 bytes each.
		  rc = SPROX_Desfire_CreateCyclicRecordFile(0, 0, 0xEEEE, 4, 10);
		  CHECK_RC();
		
		  //  Fill the Standard Data file with some data.
		  memset(abDataBuffer, 0xDA, sizeof(abDataBuffer));
		
		  rc = SPROX_Desfire_WriteData(bStdDataFileID, DF_COMM_MODE_PLAIN, 0, 640, abDataBuffer);
		  CHECK_RC();
		  rc = SPROX_Desfire_WriteData(bStdDataFileID, DF_COMM_MODE_PLAIN, 0, 30, (unsigned char *) "This is the 1st block written.");
		  CHECK_RC();
		  rc = SPROX_Desfire_WriteData(bStdDataFileID, DF_COMM_MODE_PLAIN, 34, 22, (unsigned char *) "This is the 2nd block.");
		  CHECK_RC();
		
		   //  Then make the file permanently read-only.
		  rc = SPROX_Desfire_ChangeFileSettings(bStdDataFileID, DF_COMM_MODE_PLAIN, 0xEFFF);
		  CHECK_RC();
		
		  //  Read part of the file's contents.
		  rc = SPROX_Desfire_ReadData(bStdDataFileID, DF_COMM_MODE_PLAIN, 10, 50, abDataBuffer, &dwNbBytesRead);
		  CHECK_RC();
		
		  //  Get all data in one block. 
		  //  Note: Must make sure that buffer is large enough for all data!!
		  rc = SPROX_Desfire_ReadData(bStdDataFileID, DF_COMM_MODE_PLAIN, 0, 0, abDataBuffer, &dwNbBytesRead);
		  CHECK_RC();
		
		  //  Try to overwrite the file.
		  //  Since we have made the file read-only, this should fail.
		  
		  rc = SPROX_Desfire_WriteData(bStdDataFileID, DF_COMM_MODE_PLAIN, 20, 5, "Essai");
		  if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
		    CHECK_RC();
		
		  //  Do 15 transactions.
		  for (iTransaction = 0; iTransaction < 15; iTransaction++)
		  {
		    //  Write to the Backup Data file.
		    sprintf((char *) abDataBuffer, "%02d,", iTransaction);
		    rc =
		      SPROX_Desfire_WriteData(5, DF_COMM_MODE_PLAIN, 3 * iTransaction, 3,
		                            abDataBuffer);
		    CHECK_RC();
		
		    //  Manipulate the Value file.
		    rc = SPROX_Desfire_Credit(4, DF_COMM_MODE_PLAIN, 100);
		    CHECK_RC();
		    rc = SPROX_Desfire_Debit(4, DF_COMM_MODE_PLAIN, 93);
		    CHECK_RC();
		
		    //  Write to the Cyclic Record file.
		    rc =
		      SPROX_Desfire_WriteRecord(0, DF_COMM_MODE_PLAIN, 2, 2, abDataBuffer);
		    CHECK_RC();
		    //  The following Write Record will write to the same record as above
		    rc =
		      SPROX_Desfire_WriteRecord(0, DF_COMM_MODE_PLAIN, 0, 2,
		                              (unsigned char *) "r.");
		    CHECK_RC();
		
		    //  Verify that the 'official' contents of the three files has not changed
		    //  before the CommitTransaction command.
		    //  Must make sure that buffer is large enough for all data!
		    rc =
		      SPROX_Desfire_ReadData(5, DF_COMM_MODE_PLAIN, 0, 0, abDataBuffer,
		                           &dwNbBytesRead);
		    CHECK_RC();
		    rc = SPROX_Desfire_GetValue(4, DF_COMM_MODE_PLAIN, &lAmount);
		    CHECK_RC();
		
		    //  Note: reading from an empty record file returns an error.
		    //        beginning with version 0.1 this aborts the transaction.
		    if (iTransaction != 0)
		    {
		      rc =
		        SPROX_Desfire_ReadRecords(0, DF_COMM_MODE_PLAIN, 0, 0, 4,
		                                abDataBuffer, &eNRecordsRead);
		      CHECK_RC();
		    }
		    //  Declare the transaction valid.
		    rc = SPROX_Desfire_CommitTransaction();
		    CHECK_RC();
		
		    //  Verify that the transaction has become effective.
		    //  Note: Must make sure that buffer is large enough for all data!
		    rc =
		      SPROX_Desfire_ReadData(5, DF_COMM_MODE_PLAIN, 0, 0, abDataBuffer,
		                           &dwNbBytesRead);
		    CHECK_RC();
		    rc = SPROX_Desfire_GetValue(4, DF_COMM_MODE_PLAIN, &lAmount);
		    CHECK_RC();
		    rc =
		      SPROX_Desfire_ReadRecords(0, DF_COMM_MODE_PLAIN, 0, 0, 4,
		                              abDataBuffer, &eNRecordsRead);
		    CHECK_RC();
		  }
		
		  //  Limited Credit has been disabled, so the following call should fail.
		  rc = SPROX_Desfire_LimitedCredit2(4, 20);
		  if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
		    CHECK_RC();
		
		  //  Get the file IDs of the current application.
		  rc = SPROX_Desfire_GetFileIDs(15, abDataBuffer, &bNFilesFound);
		  CHECK_RC();
		
		  //  Get information about the application's files.
		  //  Delete each file after retrieving information about it.
		  for (iFileIndex = 0; iFileIndex < bNFilesFound; iFileIndex++)
		  {
		    rc =
		      SPROX_Desfire_GetFileSettings(abDataBuffer[iFileIndex], &bFileType,
		                                  &bCommMode, &wAccessRights,
		                                  &unFileSettings);
		    CHECK_RC();
		    rc = SPROX_Desfire_DeleteFile(abDataBuffer[iFileIndex]);
		    CHECK_RC();
		  }
		
		  //  Verify that there are no files in the application.
		  rc = SPROX_Desfire_GetFileIDs(15, abDataBuffer, &bNFilesFound);
		  CHECK_RC();
		
		  //  Delete application A.
		  //  Since this application doesn't have an Application Master Key,
		  //  this requires Card Master Key authentication.
		  rc = SPROX_Desfire_SelectApplication(0);
		  CHECK_RC();
		  rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		  CHECK_RC();
		  rc = SPROX_Desfire_DeleteApplication(0xAAAAAA);
		  CHECK_RC();
		
		  //  Verify that application A has been deleted.
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		
		  //  Changing application B's keys:
		  rc = SPROX_Desfire_SelectApplication(0xBBBBBB);
		  CHECK_RC();
		
		  //  Use a TripleDES key as the Application Master Key.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(0, abNullKey);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(0, abNullKey);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, abNullKey);
		    CHECK_RC();
		  }
		
		  rc = SPROX_Desfire_GetVersion(&stVersionInfo);
		  CHECK_RC();

	
		  if (0)
		  {
		    printf("bHwVendorID=%02X\n", stVersionInfo.bHwVendorID);
		    printf("bHwType=%02X\n", stVersionInfo.bHwType);
		    printf("bHwSubType=%02X\n", stVersionInfo.bHwSubType);
		    printf("bHwMajorVersion=%02X\n", stVersionInfo.bHwMajorVersion);
		    printf("bHwMinorVersion=%02X\n", stVersionInfo.bHwMinorVersion);
		    printf("bHwStorageSize=%02X\n", stVersionInfo.bHwStorageSize);
		    printf("bHwProtocol=%02X\n", stVersionInfo.bHwProtocol);
		    printf("bSwVendorID=%02X\n", stVersionInfo.bSwVendorID);
		    printf("bSwType=%02X\n", stVersionInfo.bSwType);
		    printf("bSwSubType=%02X\n", stVersionInfo.bSwSubType);
		    printf("bSwMajorVersion=%02X\n", stVersionInfo.bSwMajorVersion);
		    printf("bSwMinorVersion=%02X\n", stVersionInfo.bSwMinorVersion);
		    printf("bSwStorageSize=%02X\n", stVersionInfo.bSwStorageSize);
		    printf("bSwProtocol=%02X\n", stVersionInfo.bSwProtocol);
		    printf("abUid=%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", stVersionInfo.abUid[0],stVersionInfo.abUid[1],stVersionInfo.abUid[2],stVersionInfo.abUid[3],stVersionInfo.abUid[4],stVersionInfo.abUid[5],stVersionInfo.abUid[6]);
		    printf("abBatchNo=%02X:%02X:%02X:%02X:%02X\n", stVersionInfo.abBatchNo[0],stVersionInfo.abBatchNo[1],stVersionInfo.abBatchNo[2],stVersionInfo.abBatchNo[3],stVersionInfo.abBatchNo[4]);
		    printf("bProductionCW=%02X\n", stVersionInfo.bProductionCW);
		    printf("bProductionYear=%02X\n", stVersionInfo.bProductionYear);
		  }
		
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_ChangeKeyAes(0, 0, appBMasterKey0, NULL); // JDA
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_ChangeKey24(0, appBMasterKey0, NULL); // JDA
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_ChangeKey(0, appBMasterKey0, NULL);
		    CHECK_RC();
		  }
		
		  //  Authenticate with the new application master key.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, appBMasterKey0);
		    CHECK_RC();
		  }
		
      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  Beginning with DesFire version 0.1 we can query the version number of a key.
		  rc = SPROX_Desfire_GetKeyVersion(0, &bKeyVersion);
		  CHECK_RC();
		
		  //  Authenticate with the new application master key.
		  //  This time use the opposite parity in all key bytes.
		  if (level & LEVEL_AES)
		  {
		
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(0, appBMasterKey1);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, appBMasterKey1);
		    CHECK_RC();
		  }
		
		  //  Change key #1 to a different SingleDES key (both key halves are the same).
		  //  Authentication with that key is necessary for changing it.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(1, 0x33, abSingleDesKey, NULL);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(1, abSingleDesKey, NULL);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(1, abSingleDesKey, NULL);
		    CHECK_RC();
		  }
		
		  //  Change key #5 to a TripeDES key.
		  //  Authentication with that key is necessary for changing it.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(5, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(5, 0x77, appBChangeKey, NULL);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(5, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(5, appBChangeKey, NULL);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(5, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(5, appBChangeKey, NULL);
		    CHECK_RC();
		  }
		
		  //  Get authenticated again with appl's Master key
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, appBMasterKey0);
		    CHECK_RC();
		  }
		
      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  Make key #5 the Change Keys Key.
		  rc = SPROX_Desfire_ChangeKeySettings(0x5F);
		  CHECK_RC();
		
		  //  Verify the new key settings.
		  rc = SPROX_Desfire_GetKeySettings(&abDataBuffer[0], &abDataBuffer[1]);
		  CHECK_RC();
		
		  //  Change keys #1 through #4 using the three key procedure.
		  //  Authentication with the Change Keys Key is now necessary for changing ordinary keys.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(5, appBChangeKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(1, 0x33, appBKey1, abSingleDesKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(2, 0x55, appBKey2, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(3, 0x33, appBKey3, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(4, 0x55, appBKey4, abNullKey);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(5, appBChangeKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(1, appBKey1, abSingleDesKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(2, appBKey2, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(3, appBKey3, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(4, appBKey4, abNullKey);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(5, appBChangeKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(1, appBKey1, abSingleDesKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(2, appBKey2, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(3, appBKey3, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(4, appBKey4, abNullKey);
		    CHECK_RC();
		  }
		
		  //  For demonstrating the three possible communication modes we create an instance
		  //  of each basic file type:
		  //  a Data file:  Read = 1, Write = 2, ReadWrite = 3, ChangeConfig = 4
		  //  a Value file: Debit = 1, LimitedCredit = 3, Credit = 2, ChangeConfig = 4
		  //  and a Linear Record file: Read = 1, Write = 3, ReadWrite = 2, ChangeConfig = 4
		  //  Note: Must make sure that buffer is large enough for all data!
		  bStdDataFileID--;
		  rc = SPROX_Desfire_CreateStdDataFile(bStdDataFileID, 0, 0x1234, 100);
		  CHECK_RC();
		  rc = SPROX_Desfire_CreateValueFile(4, 0, 0x1324, -987654321, -1000, -1000000, 1);
		  CHECK_RC();
		  rc = SPROX_Desfire_CreateLinearRecordFile(1, 0, 0x1324, 25, 4);
		  CHECK_RC();
		
      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  //  Do 7 transactions.
		  for (iTransaction = 0; iTransaction < 7; iTransaction++)
		  {
		    //  Change the communication mode for all files.
		    bCommMode = iTransaction % 3;
		    if (bCommMode == 2) bCommMode = 3;
		
		    //  This requires authentication with the key defined for changing the configuration.
		    if ((level & LEVEL_AES))
		    {
		      rc = SPROX_Desfire_AuthenticateAes(4, appBKey4);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_Authenticate24(4, appBKey4);
		      CHECK_RC();
		    } else
		    {
		      rc = SPROX_Desfire_Authenticate(4, appBKey4);
		      CHECK_RC();
		    }
		
		    rc = SPROX_Desfire_ChangeFileSettings(bStdDataFileID, bCommMode, 0x1234);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeFileSettings(4, bCommMode, 0x1324);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeFileSettings(1, bCommMode, 0x1324);
		    CHECK_RC();
		
		    //  Authenticate with the key which allows reading the files
		    if (level & LEVEL_AES)
		    {
		      rc = SPROX_Desfire_AuthenticateAes(1, appBKey1);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_Authenticate24(1, appBKey1);
		      CHECK_RC();
		    } else 
		    {
		      rc = SPROX_Desfire_Authenticate(1, appBKey1);
		      CHECK_RC();
		    }
		
		    if (iTransaction < 3)
		    {
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 1, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 2, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 3, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 4, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 5, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 6, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 7, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 8, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 12, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 16, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 32, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 40, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 48, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 64, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 0, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		
		      for (bTemp=100; bTemp>60; bTemp--)
		      {
		        rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, bTemp, abDataBuffer, &dwNbBytesRead);
		        CHECK_RC();
		        rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, bTemp, abDataBuffer, &dwNbBytesRead);
		        CHECK_RC();
		      }
		
	
		      for (bTemp=40; bTemp<60; bTemp++)
		      {
		        rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, bTemp, abDataBuffer, &dwNbBytesRead);
		        CHECK_RC();
		        rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, bTemp, abDataBuffer, &dwNbBytesRead);
		        CHECK_RC();
		      }
		
		      // Read data
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 10, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 10, 10, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 20, 10, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		      rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 30, 70, abDataBuffer, &dwNbBytesRead);
		      CHECK_RC();
		    }
		
		
		    rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 0, abDataBuffer, &dwNbBytesRead);
		    CHECK_RC();
		
		    //  Authenticate with the key which allows writing to files and increasing the Value
		    //  file's value.
		    if (level & LEVEL_AES)
		    {
		      rc = SPROX_Desfire_AuthenticateAes(2, appBKey2);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_Authenticate24(2, appBKey2);
		      CHECK_RC();
		    } else
		    {
		      rc = SPROX_Desfire_Authenticate(2, appBKey2);
		      CHECK_RC();
		    }
		
		    //  Write to the Standard Data file.
		    for (i = 0; i < 100; i++)
		      abDataBuffer[i] = ((iTransaction << 6) + i + 0);
		
		    if (iTransaction < 3)
		    {
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 8, abDataBuffer);
		      CHECK_RC();
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 16, abDataBuffer);
		      CHECK_RC();
		
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 1, abDataBuffer);
		      CHECK_RC();
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 2, abDataBuffer);
		      CHECK_RC();
		
		
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 10, abDataBuffer);
		      CHECK_RC();
		
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 10, 10, abDataBuffer);
		      CHECK_RC();
		
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 20, 10, abDataBuffer);
		      CHECK_RC();
		
		      rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 30, 70, abDataBuffer);
		      CHECK_RC();
		    }
		
		    rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 0, 100, abDataBuffer);
		    CHECK_RC();
		
		    sprintf((char *) abDataBuffer, " Transaction #%d ", iTransaction);
		    rc = SPROX_Desfire_WriteData(bStdDataFileID, bCommMode, 5, strlen((char *) abDataBuffer), abDataBuffer);
		    CHECK_RC();
		
		    //  Write to the Linear Record file.
		    //  If it turns out, that the file is full, clear its contents and repeat writing.
		    for (i = 0; i < 2; i++)
		    {
		      rc = SPROX_Desfire_WriteRecord(1, bCommMode, 0, 25,
		                                    (unsigned char *)
		                                    "0123456789012345678901234");
		      if (rc == 0)
		      {
		        sprintf((char *) abDataBuffer, " Transaction #%d ", iTransaction);
		        rc =
		          SPROX_Desfire_WriteRecord(1, bCommMode, 5,
		                                  strlen((char *) abDataBuffer),
		                                  abDataBuffer);
		      }
		      //  Was the WriteRecord successful ?
		      if (rc == 0)
		        break;              // yes
		
		      // The current authentication status has been lost. We must get authenticated again
		      if (level & LEVEL_AES)
		      {
		        rc = SPROX_Desfire_AuthenticateAes(2, appBKey2);
		        CHECK_RC();
		      } else
		      if (level & LEVEL_3DES3K)
		      {
		        rc = SPROX_Desfire_Authenticate24(2, appBKey2);
		        CHECK_RC();
		      } else
		      {
		        rc = SPROX_Desfire_Authenticate(2, appBKey2);
		        CHECK_RC();
		      }
			
		      //  Clear the record file.
		      rc = SPROX_Desfire_ClearRecordFile(1);
		      CHECK_RC();
		
		      //  It is not allowed to write to the file before a CommitTransaction.
		      //  So the following call will fail !
		      rc = SPROX_Desfire_WriteRecord(1, bCommMode, 5,
		                                    strlen((char *) abDataBuffer),
		                                    abDataBuffer);
		      if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
		        CHECK_RC();
		
		      // The current authentication status has been lost. We must get authenticated again
		      if (level & LEVEL_AES)
		      {
		        rc = SPROX_Desfire_AuthenticateAes(2, appBKey2);
		        CHECK_RC();
		      } else
		      if (level & LEVEL_3DES3K)
		      {
		        rc = SPROX_Desfire_Authenticate24(2, appBKey2);
		        CHECK_RC();
		      } else
		      {
		        rc = SPROX_Desfire_Authenticate(2, appBKey2);
		        CHECK_RC();
		      }
		
		      //  Version 0.1 and above execute an implicit AbortTransaction after any
		      //  error. Therefore the ClearRecordFile has been cancelled. We have to repeat it.
		      rc = SPROX_Desfire_ClearRecordFile(1);
		      CHECK_RC();
		
		      //  After the following the Record file is again ready for data.
		      rc = SPROX_Desfire_CommitTransaction();
		      CHECK_RC();
		    }
		
		    //  Modify the Value file.
		    rc = SPROX_Desfire_Debit(4, bCommMode, 1300);
		    CHECK_RC();
		    rc = SPROX_Desfire_Credit(4, bCommMode, 20);
		    CHECK_RC();
		    rc = SPROX_Desfire_Debit(4, bCommMode, 1700);
		    CHECK_RC();
		
		    //  Make all changes current.
		    rc = SPROX_Desfire_CommitTransaction();
		    CHECK_RC();
			
		    //  Return the whole debited amount to the Value File.
		    rc = SPROX_Desfire_LimitedCredit(4, bCommMode, 3000);
		    CHECK_RC();
		
		    //  Make the change current.
		    rc = SPROX_Desfire_CommitTransaction();
		    CHECK_RC();
		
		
		    //  Authenticate with the key which allows reading files and retrieving the Value
		    //  file's value.
		    if (level & LEVEL_AES)
		    {
		      rc = SPROX_Desfire_AuthenticateAes(1, appBKey1);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_Authenticate24(1, appBKey1);
		      CHECK_RC();
		    } else
		    {
		      rc = SPROX_Desfire_Authenticate(1, appBKey1);
		      CHECK_RC();
		    }
			
		    //  Read the first half of the Standard Data file's data specifying the exact
		    //  number of bytes to read.
		    rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 0, 50, abDataBuffer, &dwNbBytesRead);
		    CHECK_RC();
		    //  Read the second half of the data with an open read (give me all data available).
		    rc = SPROX_Desfire_ReadData(bStdDataFileID, bCommMode, 50, 0, abDataBuffer, &dwNbBytesRead);
		    CHECK_RC();
		
  	    //  Get the Value file's current balance.
		    rc = SPROX_Desfire_GetValue(4, bCommMode, &lAmount);
		    CHECK_RC();
		
		    //  Get the number of records in the Linear Record file.
		    rc = SPROX_Desfire_GetFileSettings(1, 0, 0, 0, &unFileSettings);
		    CHECK_RC();
		
		    //  Read the oldest record from the file.
		    rc =
		      SPROX_Desfire_ReadRecords(1, bCommMode,
		                              unFileSettings.stRecordFileSettings.
		                              eCurrNRecords - 1, 1,
		                              unFileSettings.stRecordFileSettings.
		                              eRecordSize, abDataBuffer, &eNRecordsRead);
		    CHECK_RC();
		
		    //  Read all records from the file.
		    rc =
		      SPROX_Desfire_ReadRecords(1, bCommMode, 0, 0,
		                              unFileSettings.stRecordFileSettings.
		                              eRecordSize, abDataBuffer, &eNRecordsRead);
		    CHECK_RC();
		  }
		
		  //  Get the file IDs of the current application.
		  rc = SPROX_Desfire_GetFileIDs(16, abDataBuffer, &bNFilesFound);
		  CHECK_RC();
		
		  //  Get information about the application's files.
		  //  Delete each file after retrieving information about it.
		  for (iFileIndex = 0; iFileIndex < bNFilesFound; iFileIndex++)
		  {
		    rc =
		      SPROX_Desfire_GetFileSettings(abDataBuffer[iFileIndex], &bFileType,
		                                  &bCommMode, &wAccessRights,
		                                  &unFileSettings);
		    CHECK_RC();
		    rc = SPROX_Desfire_DeleteFile(abDataBuffer[iFileIndex]);
		    CHECK_RC();
		  }
		
		  //  Verify that there are no files in the application.
		  rc = SPROX_Desfire_GetFileIDs(16, abDataBuffer, &bNFilesFound);
		  CHECK_RC();
		
		  //  Delete application B.
		  //  This time we can (and do) use the Application Master Key.
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(0, appBMasterKey0);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(0, appBMasterKey0);
		    CHECK_RC();
		  }
		
		  rc = SPROX_Desfire_DeleteApplication(0xBBBBBB);
		  CHECK_RC();
		
		  //  Verify that application B has been deleted.
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		
		  if (dwFreeBytes < 2000)
		  {
		    rc = SPROX_Desfire_SelectApplication(0);
		    CHECK_RC();
		    rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_FormatPICC();
		    CHECK_RC();
		
		    if (level & LEVEL_AES)
		    {
		      rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, DF_APPLSETTING2_AES | 14);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, DF_APPLSETTING2_3DES3K | 14);
		      CHECK_RC();
		    } else
		    {
		      rc = SPROX_Desfire_CreateApplication(0xCCCCCC, 0xC0, 14);
		      CHECK_RC();
		    }
		  }
		
		  //  Working with a larger file (a Cyclic Record File) using application C:
		  rc = SPROX_Desfire_SelectApplication(0xCCCCCC);
		  CHECK_RC();
		
		  //  Define keys #1 and #2 using the Change Keys key (#12).
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(12, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(1, 0, appCKey1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKeyAes(2, 0, appCKey2, abNullKey);
		    CHECK_RC();
		    // Back to master key
		    rc = SPROX_Desfire_AuthenticateAes(0, abNullKey);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(12, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(1, appCKey1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey24(2, appCKey2, abNullKey);
		    CHECK_RC();
		    // Back to master key
		    rc = SPROX_Desfire_Authenticate24(0, abNullKey);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(12, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(1, appCKey1, abNullKey);
		    CHECK_RC();
		    rc = SPROX_Desfire_ChangeKey(2, appCKey2, abNullKey);
		    CHECK_RC();
		    // Back to master key
		    rc = SPROX_Desfire_Authenticate(0, abNullKey);
		    CHECK_RC();
		  }
		
		  //  Create the file.
		  rc = SPROX_Desfire_CreateCyclicRecordFile(6, 0, 0x12E0, 100, 16);
		  CHECK_RC();
		
		  //  Do 50 transactions.
		  for (iTransaction = 0; iTransaction < 50; iTransaction++)
		  {
		    //  Change the file's communication mode.
		    bCommMode = (iTransaction % 3);
		    if (bCommMode == 2)
		      bCommMode++;
		
		    //  This requires authentication with the key defined for changing the configuration.
		    //  For this file it is the Application Master Key.
		    if (level & LEVEL_AES)
		    {
		      rc = SPROX_Desfire_AuthenticateAes(0, abNullKey);
		      CHECK_RC();
		    } else
		    if (level & LEVEL_3DES3K)
		    {
		      rc = SPROX_Desfire_Authenticate24(0, abNullKey);
		      CHECK_RC();
		    } else
		    {
		      rc = SPROX_Desfire_Authenticate(0, abNullKey);
		      CHECK_RC();
		    }
		
		
		    rc = SPROX_Desfire_ChangeFileSettings(6, bCommMode, 0x12E0);
		    CHECK_RC();
		
		    //  The file can be written using either the Write access key (0x.2..) or the
		    //  Read/Write key (0x..E.).
		    //  A valid authentication with key #2 causes the communication to take place in
		    //  the mode defined with ChangeFileSettings above.
		    //  Not being authenticated with key #2 causes the Read/Write access right to be used
		    //  forcing the communication to plain mode.
		    if (iTransaction & 4)
		    {
		      if (level & LEVEL_AES)
		      {
		        rc = SPROX_Desfire_AuthenticateAes(2, appCKey2);
		        CHECK_RC();
		      } else
		      if (level & LEVEL_3DES3K)
		      {
		        rc = SPROX_Desfire_Authenticate24(2, appCKey2);
		        CHECK_RC();
		      } else
		      {
		        rc = SPROX_Desfire_Authenticate(2, appCKey2);
		        CHECK_RC();
		      }
		
		    } else
		      bCommMode = 0;
		
		    //  Write a new record.
		    memset(abDataBuffer, 0, 100);
		    abDataBuffer[0] = iTransaction;
		    abDataBuffer[99] = iTransaction;
		    sprintf((char *) abDataBuffer + 5, " Transaction #%d ", iTransaction);
		    rc = SPROX_Desfire_WriteRecord(6, bCommMode, 0, 100, abDataBuffer);
		
		    //  Cancel every 7th WriteRecord operation.
		    if (iTransaction % 7 == 0)
		      rc = SPROX_Desfire_AbortTransaction();
		    else
		      rc = SPROX_Desfire_CommitTransaction();
		    if (rc != (DFCARD_ERROR - DF_NO_CHANGES))
		      if (rc != (DFCARD_ERROR - DF_COMMAND_ABORTED))
		        CHECK_RC();
		  }
		
		  //  Read each individual record using the designated read key.
		  //  Note that increasing the offset lets us go back in the record history.
		  //  Note also that only 22-1 records (one less than specified in CreateCyclicRecordFile)
		  //  can be accessed.
		  bCommMode = 1;
		
		  if (level & LEVEL_AES)
		  {
		    rc = SPROX_Desfire_AuthenticateAes(1, appCKey1);
		    CHECK_RC();
		  } else
		  if (level & LEVEL_3DES3K)
		  {
		    rc = SPROX_Desfire_Authenticate24(1, appCKey1);
		    CHECK_RC();
		  } else
		  {
		    rc = SPROX_Desfire_Authenticate(1, appCKey1);
		    CHECK_RC();
		  }
		
		  for (eOffset = 0; eOffset < 22; eOffset++)
		  {
		    rc = SPROX_Desfire_ReadRecords(6, bCommMode, eOffset, 1, 100, abDataBuffer, &eNRecordsRead);
		    if (rc != (DFCARD_ERROR - DF_BOUNDARY_ERROR))
		      CHECK_RC();
		  }
		
		  //  Read the whole record file with a single ReadRecords call.
		  rc = SPROX_Desfire_ReadRecords( 6, bCommMode, 0, 0, 100, abDataBuffer, &eNRecordsRead );
		  if (rc != 0)
		  {
		    printf("\nline %d, mode %d - something wrong in the library, or in the card ???\n%s\n", __LINE__, level, SPROX_Desfire_GetErrorMessage(rc));
		    rc = SPROX_Desfire_SelectApplication(0);
		    CHECK_RC();
		  }
		
		  //  Change the master key settings such that master key authentication will be required
		  //  for all card operations.
		  //  Leave the ChangeConfiguration bit (bit 3) set to allow undoing the change.
		  rc = SPROX_Desfire_SelectApplication(0);
		  CHECK_RC();
		  rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		  CHECK_RC();
		  rc = SPROX_Desfire_ChangeKeySettings(0x8);
		  CHECK_RC();
		
		  //  Clear the authentication state and try to get application IDs.
		  //  Also try to delete application C or to create a new application.
		  rc = SPROX_Desfire_SelectApplication(0);
		  CHECK_RC();
		  //  The following three calls will report an Authentication Error (0xAE).
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
		    CHECK_RC();
		  rc = SPROX_Desfire_DeleteApplication(0xCCCCCC);
		  if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
		    CHECK_RC();
		
		  // This one must fail
		  rc = SPROX_Desfire_CreateApplication(0xDDDDDD, 0xEF, 0);
		  if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
		    CHECK_RC();
		
		  //  With authentication all three should work.
		  rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		  CHECK_RC();
		  rc = SPROX_Desfire_GetApplicationIDs(32, adwApplications, &bNApplicationsFound);
		  CHECK_RC();
		  rc = SPROX_Desfire_DeleteApplication(0xCCCCCC);
		  CHECK_RC();
		  rc = SPROX_Desfire_CreateApplication(0xDDDDDD, 0xEF, 0);
		  CHECK_RC();
		
		  //  Change the master key settings back to the default which is least restrictive.
		  rc = SPROX_Desfire_ChangeKeySettings(0xF);
		  CHECK_RC();
		
		  //  Change the Card master key back to the 0 key.
		  rc = SPROX_Desfire_Authenticate(0, abCardMasterKey);
		  CHECK_RC();
		  rc = SPROX_Desfire_ChangeKey(0, abNullKey, NULL);
		  CHECK_RC();
		
		  //  Delete all demonstration data from the card.
		  rc = SPROX_Desfire_Authenticate(0, abNullKey);
		  CHECK_RC();
		
      if (!is_legacy_card)
      {		
		    rc = SPROX_Desfire_GetFreeMemory(&dwFreeBytes);
		    CHECK_RC();
      }
		
		  rc = SPROX_Desfire_FormatPICC();
		  CHECK_RC();

      printf("\n");
    }

    printf("\n");
    printf("All tests have been successfully passed\n");

    goto tag_stop;

  tag_stop:

    /* T=CL (ISO 14443-4) tag stop */
    /* --------------------------- */

    rc = SPROX_TclA_Deselect(cid);
    if (rc != MI_OK)
    {
      printf("T=CL DESELECT failed (%d)\n", rc);
      goto tag_halt;
    }

  tag_halt:

    /* ISO 14443-3 tag stop */
    /* -------------------- */

    rc = SPROX_TclA_Halt();
    if (rc != MI_OK)
    {
      printf("HALT failed\n");
      goto close;
    }

    /* Another tag in the field ? */
    /* -------------------------- */
    goto next_tag;

  close:
    SPROX_ControlRF(FALSE);
    SPROX_ReaderClose();

  done:
    /* Display last error */
    if (rc == MI_OK)
    {
      printf("Done\n");
    } else
    {
      printf("%s (%d)\n", SPROX_GetErrorMessage(rc), rc);
    }
#ifdef LOOP_TEST
    loop_count++;
    printf("--> %d error(s) after %d loop(s)\n", err_count, loop_count);
  }
#endif
  return 0;
}
